package com.sunwayworld.basemodule.business.batch.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.sunwayworld.basemodule.basedata.batchtype.bean.LimsBatchCategoryBean;
import com.sunwayworld.basemodule.basedata.batchtype.service.LimsBatchCategoryService;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchBean;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchSampleBean;
import com.sunwayworld.basemodule.business.batch.bean.LimsBatchSampleProductBean;
import com.sunwayworld.basemodule.business.batch.dao.LimsBatchDao;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleProductService;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchSampleService;
import com.sunwayworld.basemodule.business.batch.service.LimsBatchService;
import com.sunwayworld.basemodule.business.pjtask.service.LimsPjFolderService;
import com.sunwayworld.basemodule.business.prefolder.service.LimsPreFolderService;
import com.sunwayworld.basemodule.common.auditrecord.service.LimsAuditRecordService;
import com.sunwayworld.basemodule.samplemanage.sample.bean.LimsSampleBean;
import com.sunwayworld.basemodule.samplemanage.sample.service.LimsSampleService;
import com.sunwayworld.framework.at.annotation.AuditTrailEntry;
import com.sunwayworld.framework.at.annotation.AuditTrailType;
import com.sunwayworld.framework.constant.Constant;
import com.sunwayworld.framework.context.ApplicationContextHelper;
import com.sunwayworld.framework.context.concurrent.GikamConcurrentLocker;
import com.sunwayworld.framework.exception.InvalidDataException;
import com.sunwayworld.framework.i18n.I18nHelper;
import com.sunwayworld.framework.mybatis.mapper.MapperParameter;
import com.sunwayworld.framework.mybatis.mapper.MatchPattern;
import com.sunwayworld.framework.mybatis.mapper.SearchFilter;
import com.sunwayworld.framework.restful.data.RestJsonWrapperBean;
import com.sunwayworld.framework.spring.annotation.GikamBean;
import com.sunwayworld.framework.support.PersistableHelper;
import com.sunwayworld.framework.utils.CollectionUtils;
import com.sunwayworld.framework.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Repository
@GikamBean
public class LimsBatchServiceImpl implements LimsBatchService {

    @Autowired
    private LimsBatchDao limsBatchDao;

    @Lazy
    @Autowired
    private LimsSampleService sampleService;

    @Lazy
    @Autowired
    private LimsBatchSampleService batchSampleService;

    @Lazy
    @Autowired
    private LimsBatchSampleProductService sampleProductService;

    @Lazy
    @Autowired
    private LimsAuditRecordService auditRecordService;

    @Lazy
    @Autowired
    private LimsPreFolderService preFolderService;

    @Lazy
    @Autowired
    private LimsPjFolderService pjFolderService;

    @Lazy
    @Autowired
    private LimsBatchCategoryService batchCategoryService;

    @Override
    @SuppressWarnings("unchecked")
    public LimsBatchDao getDao() {
        return limsBatchDao;
    }

    @Override
    @Transactional
    @AuditTrailEntry(AuditTrailType.INSERT)
    public Long insert(RestJsonWrapperBean jsonWrapper) {
        LimsBatchBean limsBatch = jsonWrapper.parseUnique(LimsBatchBean.class);
        limsBatch.setId(ApplicationContextHelper.getNextIdentity());
        limsBatch.setBatchCode(ApplicationContextHelper.getNextSequence(getDao().getTable(), "D"));
        LimsBatchCategoryBean limsBatchCategoryBean = batchCategoryService.selectFirstByFilter(SearchFilter.instance()
                .match("batchTypeCode", limsBatch.getBatchType()).filter(MatchPattern.EQ));
        if (limsBatchCategoryBean != null) {
            limsBatch.setBatchCategory(limsBatchCategoryBean.getBatchCategory());
        }
        getDao().insert(limsBatch);
        return limsBatch.getId();
    }

    @Transactional
    @Override
    public void submit(RestJsonWrapperBean wrapper) {
        List<LimsBatchBean> batchBeans = wrapper.parse(LimsBatchBean.class);
        LocalDateTime now = LocalDateTime.now();
        batchBeans.forEach(b -> {
            b.setStatus("approve");
            b.setEditSubmitTime(now);
        });
        getDao().fastUpdate(batchBeans, "status", "editSubmitTime");

        List<Long> ids = batchBeans.stream().map(LimsBatchBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(ids, "T_LIMS_BATCH", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        MapperParameter parameter = new MapperParameter();
        parameter.put("batchIds", StringUtils.join(ids, ","));
        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

    }

    @Transactional
    @Override
    public void batchApprove(RestJsonWrapperBean wrapper) {
        List<LimsBatchBean> from = wrapper.parse(LimsBatchBean.class);
        List<Long> ids = from.stream().map(LimsBatchBean::getId).filter(Objects::nonNull).collect(Collectors.toList());
        if (ids.isEmpty()) {
            return;
        }
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        GikamConcurrentLocker.block(LocalDateTime.now().format(df));

        List<LimsBatchBean> realBeans = this.selectListByFilter(SearchFilter.instance().match("id", ids).filter(MatchPattern.OR).match("status", "approve").filter(MatchPattern.SC));
        ids = realBeans.stream().map(LimsBatchBean::getId).collect(Collectors.toList());
        if (ids.isEmpty()) {
            return;
        }

        MapperParameter parameter = new MapperParameter();
        parameter.put("batchIds", StringUtils.join(ids, ","));
        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
        LocalDateTime dateTime = LocalDateTime.now();
        realBeans.forEach(b -> {
            b.setStatus("done");
            b.setSubmitTime(dateTime);
        });
        List<LimsSampleBean> sampleDone = new ArrayList<>();
        List<Long> batchSampleIdList = sampleBeans.stream().map(s -> Long.parseLong(s.getExt$Item("batchSampleId"))).distinct().collect(Collectors.toList());
        List<LimsBatchSampleProductBean> productBeans = sampleProductService.getDao().selectListByOneColumnValues(batchSampleIdList, "batchSampleId");
        sampleBeans.forEach(s -> {
            if (Constant.NO.equals(s.getExt$Item("selected"))) {
                s.setStatus("receive");
            } else {
                s.setStatus("inExperiment");
                sampleDone.add(s);
            }
            productBeans.stream().filter(p -> p.getBatchSampleId().equals(Long.parseLong(s.getExt$Item("batchSampleId"))))
                    .forEach(e -> e.setStatus(s.getStatus()));
        });
        sampleProductService.getDao().fastUpdate(productBeans, "status");
        getDao().fastUpdate(realBeans, "status", "submitTime");
        sampleService.getDao().fastUpdate(sampleBeans, "status");

        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_APPROVE"), I18nHelper.getMessage("GIKAM.WORKFLOW.BUTTON.PASS"), null);
        auditRecordService.insertAuditRecords(ids, "T_LIMS_BATCH", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_APPROVE"), I18nHelper.getMessage("GIKAM.WORKFLOW.BUTTON.PASS"), null);

        if (!CollectionUtils.isEmpty(sampleDone)) {
            // 进入实验
            List<LimsSampleBean> tjSampleBeans = sampleDone.stream().filter(s -> "TJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
            List<LimsSampleBean> pjSampleBeans = sampleDone.stream().filter(s -> "PJ".equalsIgnoreCase(s.getExt$Item("batchCategory"))).collect(Collectors.toList());
            preFolderService.insertPreFolders(tjSampleBeans);
            pjFolderService.insertPjFolders(pjSampleBeans);
//            ExecutorHelper.submit(() -> preFolderService.insertPreFolders(tjSampleBeans));// 特检
//            ExecutorHelper.submit(() -> pjFolderService.insertPjFolders(pjSampleBeans));// 普检
        }
    }

    @Transactional
    @Override
    public void batchReject(RestJsonWrapperBean wrapper) {
        String reason = wrapper.getParamValue("reason");
        List<LimsBatchBean> batchBeans = wrapper.parse(LimsBatchBean.class);
        if (batchBeans.isEmpty()) {
            return;
        }
        batchBeans.forEach(b -> b.setStatus("draft_reject"));
        getDao().fastUpdate(batchBeans, "status");
        List<Long> ids = batchBeans.stream().map(LimsBatchBean::getId).filter(Objects::nonNull).collect(Collectors.toList());
        if (ids.isEmpty()) {
            return;
        }
        auditRecordService.insertAuditRecords(ids, "T_LIMS_BATCH", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_APPROVE"), I18nHelper.getMessage("GIKAM.WORKFLOW.BUTTON.REJECT"), reason);

        MapperParameter parameter = new MapperParameter();
        parameter.put("batchIds", StringUtils.join(ids, ","));
        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_APPROVE"), I18nHelper.getMessage("GIKAM.WORKFLOW.BUTTON.REJECT"), reason);

    }

    @Override
    public void submitById(Long id, RestJsonWrapperBean wrapper) {
        LimsBatchBean batchBean = new LimsBatchBean();
        batchBean.setId(id);
        batchBean.setStatus("approve");
        batchBean.setEditSubmitTime(LocalDateTime.now());
        getDao().update(batchBean, "status", "editSubmitTime");
        auditRecordService.insertAuditRecords(Collections.singletonList(id), "T_LIMS_BATCH", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        MapperParameter parameter = new MapperParameter();
        parameter.put("batchIds", batchBean.getId().toString());
        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

//        MapperParameter parameter = new MapperParameter();
//        parameter.setFilter(SearchFilter.instance().match("batchId", id).filter(MatchPattern.EQ));
//        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
//        List<LimsBatchSampleProductBean> sampleProductBeans = sampleProductService.selectListByFilter(SearchFilter.instance()
//                .match("batchId", id).filter(MatchPattern.EQ));
//
//        LimsBatchBean batchBean = new LimsBatchBean();
//        batchBean.setId(id);
//        batchBean.setStatus("done");
//        getDao().update(batchBean, "status");
//
//        if (Constant.NO.equals(sampleBeans.get(0).getExt$Item("selected"))) {
//            sampleBeans.forEach(s -> s.setStatus("receive"));
//            sampleProductBeans.forEach(s -> s.setStatus("receive"));
//        } else {
//            sampleBeans.forEach(s -> s.setStatus("inExperiment"));
//            sampleProductBeans.forEach(s -> s.setStatus("inExperiment"));
//            // 进入实验的生成 PreFolder
//            preFolderService.insertPreFolders(sampleBeans);
//        }
//        sampleService.getDao().update(sampleBeans, "status");
//        sampleProductService.getDao().update(sampleProductBeans, "status");
//
//        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
//        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_ENTER"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);
    }

    @Override
    @Transactional
    public void delete(RestJsonWrapperBean wrapper) {
        List<LimsBatchBean> parse = wrapper.parse(LimsBatchBean.class);
        if (CollectionUtils.isEmpty(parse)) return;
        List<Long> idList = parse.stream().map(LimsBatchBean::getId).collect(Collectors.toList());
        List<LimsBatchBean> batchBeans = selectListByIds(idList);
        // 级联删除
        List<Long> ids = batchBeans.stream().filter(b -> Constant.NO.equals(b.getSelected())).map(LimsBatchBean::getId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(ids)) {
            // 非选择过来的样本，一并删除
            MapperParameter parameter = new MapperParameter();
            parameter.setFilter(SearchFilter.instance().match("batchId", ids).filter(MatchPattern.OR));
            List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
            sampleService.getDao().deleteBy(sampleBeans);
        }
        List<LimsBatchSampleProductBean> productBeans = new ArrayList<>();
        List<LimsBatchSampleBean> batchSampleBeans = new ArrayList<>();
        for (LimsBatchBean batchBean : batchBeans) {
            LimsBatchSampleProductBean productBean = new LimsBatchSampleProductBean();
            productBean.setBatchId(batchBean.getId());
            productBeans.add(productBean);
            LimsBatchSampleBean batchSampleBean = new LimsBatchSampleBean();
            batchSampleBean.setBatchId(batchBean.getId());
            batchSampleBeans.add(batchSampleBean);
        }
        batchSampleService.getDao().deleteBy(batchSampleBeans, "batchId");
        sampleProductService.getDao().deleteBy(productBeans, "batchId");
        getDao().deleteBy(batchBeans);
    }

    @Override
    public LimsBatchBean selectForBatchDetailPage(Long id) {
        MapperParameter parameter = new MapperParameter();
        parameter.put("id", id);
        List<LimsBatchBean> collect = getDao().selectForBatchDetailPage(parameter).stream()
                .map(m -> PersistableHelper.mapToPersistable(m, LimsBatchBean.class)).collect(Collectors.toList());
        return collect.get(0);
    }

    @Override
    public JSONObject recallBatch(RestJsonWrapperBean wrapper) {
        JSONObject req = new JSONObject();
        req.put("flag", "1");
//        StringBuffer message = new StringBuffer();

        List<LimsBatchBean> batchBeans = wrapper.parse(LimsBatchBean.class);
        List<Long> ids = batchBeans.stream().map(LimsBatchBean::getId).collect(Collectors.toList());
        batchBeans = this.selectListByIds(ids);
        if (batchBeans.stream().anyMatch(b -> b.getStatus().equals("done"))) {
            throw new InvalidDataException("送检单已经审核通过，无法召回！");
        }
        MapperParameter parameter = new MapperParameter();
        parameter.put("batchIds", StringUtils.join(ids, ","));
        List<LimsSampleBean> sampleBeans = batchSampleService.selectBatchSample(parameter);
        LocalDateTime dateTime = LocalDateTime.now();
        batchBeans.forEach(b -> {
            b.setStatus("draft_recall");
            b.setSubmitTime(dateTime);
        });
        List<LimsSampleBean> sampleDone = new ArrayList<>();
        List<LimsBatchSampleProductBean> productBeans = new ArrayList<>();
        sampleBeans.forEach(s -> {
//            if (!s.getStatus().equals("receive")) {
//                message.append(s.getSampleCode()).append("<br/>");
//            }
            if (Constant.NO.equals(s.getExt$Item("selected"))) {
                s.setStatus("draft");
            } else {
//                s.setStatus("inExperiment");
//                sampleDone.add(s);
            }
            LimsBatchSampleProductBean productBean = new LimsBatchSampleProductBean();
            productBean.setBatchSampleId(Long.parseLong(s.getExt$Item("batchSampleId")));
            productBean.setStatus(s.getStatus());
            productBeans.add(productBean);
        });

//        if (message.length() > 0) {
//            req.put("flag", "0");
//            message.append("订单下样本已入库，不能召回");
//            req.put("message", message);
//            return req;
//        }

        sampleProductService.getDao().update(productBeans, Collections.singletonList("status"), "batchSampleId");
        getDao().update(batchBeans, "status", "submitTime");
        sampleService.getDao().update(sampleBeans, "status");

        List<Long> idList = sampleBeans.stream().map(LimsSampleBean::getId).collect(Collectors.toList());
        auditRecordService.insertAuditRecords(idList, "T_LIMS_SAMPLE", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_RECALL"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);
        auditRecordService.insertAuditRecords(ids, "T_LIMS_BATCH", I18nHelper.getMessage("LIMS.MODULE.MENUS.TREE.BATCH_RECALL"), I18nHelper.getMessage("GIKAM.MODAL.SUBMIT"), null);

        return req;
    }

    @Override
    public LimsBatchCategoryBean batchCategory(RestJsonWrapperBean wrapperBean) {
        LimsBatchBean batchBean = wrapperBean.parseUnique(LimsBatchBean.class);
        if (batchBean == null || batchBean.getId() == null) {
            return null;
        }
        batchBean = this.getDao().selectByIdIfPresent(batchBean.getId());
        if (StringUtils.isBlank(batchBean.getBatchType())) {
            return null;
        }
        LimsBatchCategoryService limsBatchCategoryService = ApplicationContextHelper.getBean(LimsBatchCategoryService.class);
        return limsBatchCategoryService.selectFirstByFilter(SearchFilter.instance().match("batchTypeCode", batchBean.getBatchType()).filter(MatchPattern.EQ));
    }
}
